之前介紹的Outbox Pattern可能需要透過排程或是MQ來做訊息交換.設計上會稍微複雜, 要引入MQ
Saga不必引入MQ, 因為是透過多次外部系統之間的通訊, 才能把整個事務從開始狀態轉成結束狀態.
但需要使用對策Countermeasure, 來防止或是減少由於缺少事務隔離而導致的併發異常.
1987年Hector & Kenneth發表Saga論文.
Saga也是微服務架構中維護資料一致性的機制.透過一來串的本地事務組成, 每一個本地事務負責更新它所在服務的私有資料庫. 所以這些本地事務還是依賴於ACID; 每一個本地事務的完成會觸發下一個本地事務的執行.
Saga有個別名叫做Long-lived transaction(長事務), 這裡的長指的是跨越系統邊界的多次事務.核心概念是避免事務長時間持有對資源的鎖, 應該把長事務切分成一組按順序提交的短事務.
因為把長事務切成很多小的本地事務, 所以每個Saga會由一系列的sub-transaction Ti組成.
Saga依照正常事務(T1...Tn)依序執行.
本地ACID事務可以對資料進行Rollback,
但Saga沒辦法, 因為每個步驟都會把變更提交到本地資料庫,
依靠的是一種策略叫做"Compensation Transaction"的補償事務機制.
所以每個Ti都有對應的補償事務Ci.
如果第j個sub-transaction發生問題, 則開始對j之前的sub-transaction開始反向做補償
Saga依照正常事務(T1...Tj)的反向順序來依序執行補償事務(Cj...C1), 其中0 < j < n.
補償跟原來的Rollback不同, Rollback是真的可以恢復成原有的狀態, 但補償算是一種沖正的概念, 像是您在Line上發給女友一則訊息, 您也無法真的收回, 也只能用一則新的訊息"您已收回"的訊息, 指向原本的訊息ID, 然後做覆蓋, 原有的訊息狀態更改為"收回"; 因為您也無法跑到人家的裝置上刪除資訊XD
如果沒把資料庫做拆分, 滿足ACID的資料庫只要庫存不足或錯誤, 大家都在本機事務上, 其實訂單是不會成立的, 會直接Rollback.
但BASE下雖然最終訂單被Cancelled, 但其實訂單還是產生了QQ
以上篇的例子Order與Inventory這次在加入User作為例子.
事務情境是, 建立訂單後檢查庫存, 若庫存正常替用戶扣款, 扣款成功則訂單完成.
我們把訂單, 商品, 用戶拆成三個獨立的服務並各自用私有的資料庫.
正常流程如下圖
這樣的模式, 每一段小事務只需要鎖定本地資料庫的資料極短的時間.
但這種模式, 很難輕易Rollback, 只能透過補償(Compensation)機制來達到最終一致性(Eventually Consistent).
如上面的情境, 要是T2失敗, Order服務就要有接口可以對T1的事務做C1補償
要是T4的扣款失敗, 前面的T3,T2,T1都得做補償C3->C2->C1
當然補償事務理論上不會失敗, 但真實情況就是可能會失敗, 主機硬碟網路電力等等的問題.
慢慢來研究怎處理.
回到第一段Saga因為缺乏ACID的事務隔離特性, 所以其實Saga模式只滿足了ACD三個特性.
每個Saga的本地事務所作的更改, 會立刻被其他Saga給看到.
這樣會有幾個問題.
這就回到第三篇曾提到的Isolation 隔離性, 但沒講到的那幾個事務隔離級別要防範的Read現象.
明天再來慢慢往下講了